package main

import "fmt"

/** 并发: channel通信机制: 消息通道
0、···· channel是不同goruntine之间异步通信的一种数据结构 ···
1、channel是个引用类型(初始化时默认为nil)，且必须指明类型
2、已经关闭的channel不能继续发送消息，但是可以继续取数据(直至取完，如果一直获取则输出0)
3、对于一个通道，读与写的次数必须对等，且必须有读有写才会形成一个通道
*/

func useCacheChannel() {
	ch := make(chan int, 10) // 创建一个容量为10的有缓冲区通道
	ch <- 10                 // 写，放入
	x := <-ch                // 读，取值
	fmt.Println(x)           // 10

	// x1, ok := <-ch 		 // 读，取值，同时返回一个bool值判断是否读取成功
	// if ok {
	// 	fmt.Println("err:", ok)
	// }
	// fmt.Println("x1:", x1)
	close(ch)
}

func UnUseCacheChannel() {
	ch := make(chan int) // 创建一个无缓冲区通道, 又称为同步通道(需要手动解决缓存的值)
	ch <- 10             // ch <- 10这一行代码形成死锁
	fmt.Println("发送成功")
	close(ch)
}

func nilCacheChannel() {
	var names chan string

	names <- "hello world"
	fmt.Println("names: ", <-names) // 由于names是nil的，写操作会阻塞在这里，所以程序运行到这里会发生奔溃
}

func recv(c chan int) {
	ret := <-c
	fmt.Println("接受成功", ret)
}

func main() {
	// 1. 使用 有缓冲区的channel
	// 当缓冲写满时，写的动作阻塞；当被读取时，再恢复写入
	// 当缓冲区读取完毕，读阻塞
	useCacheChannel()

	// 2. 使用 无缓冲区的channel
	// UnUseCacheChannel()

	// 3. 使用 nil的channel
	// 如果管道没有使用make分配空间，那么管道默认是nil的，读取、写入都会阻塞
	// nilCacheChannel()

	// 3. 启用一个goroutine去接收值
	ch := make(chan int)
	go recv(ch)
	ch <- 10
	fmt.Println("发送成功")
	close(ch)

	// 4. 单向通道
	// 单向读通道
	// var sigleReadChannel <-chan string
	// 单向写通道
	// var sigleWriteChannel chan<- string
}
